/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* vim: set ts=8 sts=2 et sw=2 tw=80: *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"mozilla/ArrayUtils.h"#include"mozilla/DeclarationBlockInlines.h"#include"mozilla/EventDispatcher.h"#include"mozilla/EventListenerManager.h"#include"mozilla/EventStateManager.h"#include"mozilla/EventStates.h"#include"mozilla/GenericSpecifiedValuesInlines.h"#include"mozilla/Likely.h"#include"mozilla/MouseEvents.h"#include"mozilla/TextEditor.h"#include"nscore.h"#include"nsGenericHTMLElement.h"#include"nsAttrValueInlines.h"#include"nsCOMPtr.h"#include"nsIAtom.h"#include"nsQueryObject.h"#include"nsIContentInlines.h"#include"nsIContentViewer.h"#include"mozilla/css/Declaration.h"#include"nsIDocument.h"#include"nsIDocumentEncoder.h"#include"nsIDOMHTMLDocument.h"#include"nsIDOMAttr.h"#include"nsIDOMDocumentFragment.h"#include"nsIDOMHTMLElement.h"#include"nsIDOMHTMLMenuElement.h"#include"nsIDOMWindow.h"#include"nsIDOMDocument.h"#include"nsMappedAttributes.h"#include"nsHTMLStyleSheet.h"#include"nsIHTMLDocument.h"#include"nsPIDOMWindow.h"#include"nsIURL.h"#include"nsEscape.h"#include"nsIFrameInlines.h"#include"nsIScrollableFrame.h"#include"nsView.h"#include"nsViewManager.h"#include"nsIWidget.h"#include"nsRange.h"#include"nsIPresShell.h"#include"nsPresContext.h"#include"nsIDocShell.h"#include"nsNameSpaceManager.h"#include"nsError.h"#include"nsIPrincipal.h"#include"nsContainerFrame.h"#include"nsStyleUtil.h"#include"nsPresState.h"#include"nsILayoutHistoryState.h"#include"nsHTMLParts.h"#include"nsContentUtils.h"#include"mozilla/dom/DirectionalityUtils.h"#include"nsString.h"#include"nsUnicharUtils.h"#include"nsGkAtoms.h"#include"nsIDOMEvent.h"#include"nsDOMCSSDeclaration.h"#include"nsITextControlFrame.h"#include"nsIForm.h"#include"nsIFormControl.h"#include"nsIDOMHTMLFormElement.h"#include"mozilla/dom/HTMLFormElement.h"#include"nsFocusManager.h"#include"nsAttrValueOrString.h"#include"mozilla/InternalMutationEvent.h"#include"nsDOMStringMap.h"#include"nsIEditor.h"#include"nsLayoutUtils.h"#include"mozAutoDocUpdate.h"#include"nsHtml5Module.h"#include"nsITextControlElement.h"#include"mozilla/dom/Element.h"#include"HTMLFieldSetElement.h"#include"nsTextNode.h"#include"HTMLBRElement.h"#include"HTMLMenuElement.h"#include"nsDOMMutationObserver.h"#include"mozilla/Preferences.h"#include"mozilla/dom/FromParser.h"#include"mozilla/dom/Link.h"#include"mozilla/BloomFilter.h"#include"mozilla/dom/ScriptLoader.h"#include"nsVariant.h"#include"nsDOMTokenList.h"#include"nsThreadUtils.h"#include"nsTextFragment.h"#include"mozilla/dom/BindingUtils.h"#include"mozilla/dom/TouchEvent.h"#include"mozilla/ErrorResult.h"#include"nsHTMLDocument.h"#include"nsGlobalWindow.h"#include"mozilla/dom/HTMLBodyElement.h"#include"imgIContainer.h"#include"nsComputedDOMStyle.h"#include"mozilla/StyleSetHandle.h"#include"mozilla/StyleSetHandleInlines.h"#include"ReferrerPolicy.h"#include"mozilla/dom/HTMLLabelElement.h"usingnamespacemozilla;usingnamespacemozilla::dom;/** * nsAutoFocusEvent is used to dispatch a focus event when a * nsGenericHTMLFormElement is binded to the tree with the autofocus attribute * enabled. */classnsAutoFocusEvent:publicRunnable{public:explicitnsAutoFocusEvent(nsGenericHTMLFormElement*aElement):mozilla::Runnable("nsAutoFocusEvent"),mElement(aElement){}NS_IMETHODRun()override{nsFocusManager*fm=nsFocusManager::GetFocusManager();if(!fm){returnNS_ERROR_NULL_POINTER;}nsIDocument*document=mElement->OwnerDoc();nsPIDOMWindowOuter*window=document->GetWindow();if(!window){returnNS_OK;}// Trying to found the top window (equivalent to window.top).if(nsCOMPtr<nsPIDOMWindowOuter>top=window->GetTop()){window=top;}if(window->GetFocusedNode()){returnNS_OK;}nsCOMPtr<nsIDocument>topDoc=window->GetExtantDoc();if(topDoc&&topDoc->GetReadyStateEnum()==nsIDocument::READYSTATE_COMPLETE){returnNS_OK;}// If something is focused in the same document, ignore autofocus.if(!fm->GetFocusedContent()||fm->GetFocusedContent()->OwnerDoc()!=document){mozilla::ErrorResultrv;mElement->Focus(rv);returnrv.StealNSResult();}returnNS_OK;}private:// NOTE: nsGenericHTMLFormElement is saved as a nsGenericHTMLElement// because AddRef/Release are ambiguous with nsGenericHTMLFormElement// and Focus() is declared (and defined) in nsGenericHTMLElement class.RefPtr<nsGenericHTMLElement>mElement;};NS_IMPL_ADDREF_INHERITED(nsGenericHTMLElement,nsGenericHTMLElementBase)NS_IMPL_RELEASE_INHERITED(nsGenericHTMLElement,nsGenericHTMLElementBase)NS_INTERFACE_MAP_BEGIN(nsGenericHTMLElement)NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLElement)NS_INTERFACE_MAP_ENTRY(nsIDOMElement)NS_INTERFACE_MAP_ENTRY(nsIDOMNode)NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElementBase)nsresultnsGenericHTMLElement::CopyInnerTo(Element*aDst,boolaPreallocateChildren){MOZ_ASSERT(!aDst->GetUncomposedDoc(),"Should not CopyInnerTo an Element in a document");nsresultrv;boolreparse=(aDst->OwnerDoc()!=OwnerDoc());rv=static_cast<nsGenericHTMLElement*>(aDst)->mAttrsAndChildren.EnsureCapacityToClone(mAttrsAndChildren,aPreallocateChildren);NS_ENSURE_SUCCESS(rv,rv);int32_ti,count=GetAttrCount();for(i=0;i<count;++i){constnsAttrName*name=mAttrsAndChildren.AttrNameAt(i);constnsAttrValue*value=mAttrsAndChildren.AttrAt(i);if(name->Equals(nsGkAtoms::style,kNameSpaceID_None)&&value->Type()==nsAttrValue::eCSSDeclaration){// We still clone CSS attributes, even in the cross-document case.// https://github.com/w3c/webappsec-csp/issues/212// We can't just set this as a string, because that will fail// to reparse the string into style data until the node is// inserted into the document. Clone the Rule instead.nsAttrValuevalueCopy(*value);rv=aDst->SetParsedAttr(name->NamespaceID(),name->LocalName(),name->GetPrefix(),valueCopy,false);NS_ENSURE_SUCCESS(rv,rv);DeclarationBlock*cssDeclaration=value->GetCSSDeclarationValue();cssDeclaration->SetImmutable();}elseif(reparse){nsAutoStringvalStr;value->ToString(valStr);rv=aDst->SetAttr(name->NamespaceID(),name->LocalName(),name->GetPrefix(),valStr,false);NS_ENSURE_SUCCESS(rv,rv);}else{nsAttrValuevalueCopy(*value);rv=aDst->SetParsedAttr(name->NamespaceID(),name->LocalName(),name->GetPrefix(),valueCopy,false);NS_ENSURE_SUCCESS(rv,rv);}}returnNS_OK;}NS_IMETHODIMPnsGenericHTMLElement::GetDataset(nsISupports**aDataset){*aDataset=Dataset().take();returnNS_OK;}staticconstnsAttrValue::EnumTablekDirTable[]={{"ltr",eDir_LTR},{"rtl",eDir_RTL},{"auto",eDir_Auto},{nullptr,0}};voidnsGenericHTMLElement::GetAccessKeyLabel(nsString&aLabel){nsAutoStringsuffix;GetAccessKey(suffix);if(!suffix.IsEmpty()){EventStateManager::GetAccessKeyLabelPrefix(this,aLabel);aLabel.Append(suffix);}}staticboolIS_TABLE_CELL(LayoutFrameTypeframeType){returnLayoutFrameType::TableCell==frameType||LayoutFrameType::BCTableCell==frameType;}staticboolIsOffsetParent(nsIFrame*aFrame){LayoutFrameTypeframeType=aFrame->Type();if(IS_TABLE_CELL(frameType)||frameType==LayoutFrameType::Table){// Per the IDL for Element, only td, th, and table are acceptable offsetParents// apart from body or positioned elements; we need to check the content type as// well as the frame type so we ignore anonymous tables created by an element// with display: table-cell with no actual tablensIContent*content=aFrame->GetContent();returncontent->IsAnyOfHTMLElements(nsGkAtoms::table,nsGkAtoms::td,nsGkAtoms::th);}returnfalse;}Element*nsGenericHTMLElement::GetOffsetRect(CSSIntRect&aRect){aRect=CSSIntRect();nsIFrame*frame=GetStyledFrame();if(!frame){returnnullptr;}nsIFrame*parent=frame->GetParent();nsPointorigin(0,0);if(parent&&parent->IsTableWrapperFrame()&&frame->IsTableFrame()){origin=parent->GetPositionIgnoringScrolling();parent=parent->GetParent();}nsIContent*offsetParent=nullptr;Element*docElement=GetComposedDoc()->GetRootElement();nsIContent*content=frame->GetContent();if(content&&(content->IsHTMLElement(nsGkAtoms::body)||content==docElement)){parent=frame;}else{constboolisPositioned=frame->IsAbsPosContainingBlock();constboolisAbsolutelyPositioned=frame->IsAbsolutelyPositioned();origin+=frame->GetPositionIgnoringScrolling();for(;parent;parent=parent->GetParent()){content=parent->GetContent();// Stop at the first ancestor that is positioned.if(parent->IsAbsPosContainingBlock()){offsetParent=content;break;}// Add the parent's origin to our own to get to the// right coordinate system.constboolisOffsetParent=!isPositioned&&IsOffsetParent(parent);if(!isAbsolutelyPositioned&&!isOffsetParent){origin+=parent->GetPositionIgnoringScrolling();}if(content){// If we've hit the document element, break here.if(content==docElement){break;}// Break if the ancestor frame type makes it suitable as offset parent// and this element is *not* positioned or if we found the body element.if(isOffsetParent||content->IsHTMLElement(nsGkAtoms::body)){offsetParent=content;break;}}}if(isAbsolutelyPositioned&&!offsetParent){// If this element is absolutely positioned, but we don't have// an offset parent it means this element is an absolutely// positioned child that's not nested inside another positioned// element, in this case the element's frame's parent is the// frame for the HTML element so we fail to find the body in the// parent chain. We want the offset parent in this case to be// the body, so we just get the body element from the document.nsCOMPtr<nsIDOMHTMLDocument>html_doc(do_QueryInterface(GetComposedDoc()));if(html_doc){offsetParent=static_cast<nsHTMLDocument*>(html_doc.get())->GetBody();}}}// Subtract the parent border unless it uses border-box sizing.if(parent&&parent->StylePosition()->mBoxSizing!=StyleBoxSizing::Border){constnsStyleBorder*border=parent->StyleBorder();origin.x-=border->GetComputedBorderWidth(eSideLeft);origin.y-=border->GetComputedBorderWidth(eSideTop);}// XXX We should really consider subtracting out padding for// content-box sizing, but we should see what IE does....// Get the union of all rectangles in this and continuation frames.// It doesn't really matter what we use as aRelativeTo here, since// we only care about the size. We just have to use something non-null.nsRectrcFrame=nsLayoutUtils::GetAllInFlowRectsUnion(frame,frame);rcFrame.MoveTo(origin);aRect=CSSIntRect::FromAppUnitsRounded(rcFrame);returnoffsetParent?offsetParent->AsElement():nullptr;}NS_IMETHODIMPnsGenericHTMLElement::InsertAdjacentHTML(constnsAString&aPosition,constnsAString&aText){ErrorResultrv;Element::InsertAdjacentHTML(aPosition,aText,rv);returnrv.StealNSResult();}boolnsGenericHTMLElement::Spellcheck(){// Has the state has been explicitly set?nsIContent*node;for(node=this;node;node=node->GetParent()){if(node->IsHTMLElement()){staticnsIContent::AttrValuesArraystrings[]={&nsGkAtoms::_true,&nsGkAtoms::_false,nullptr};switch(node->FindAttrValueIn(kNameSpaceID_None,nsGkAtoms::spellcheck,strings,eCaseMatters)){case0:// spellcheck = "true"returntrue;case1:// spellcheck = "false"returnfalse;}}}// contenteditable/designMode are spellchecked by defaultif(IsEditable()){returntrue;}// Is this a chrome element?if(nsContentUtils::IsChromeDoc(OwnerDoc())){returnfalse;// Not spellchecked by default}// Anything else that's not a form control is not spellchecked by defaultnsCOMPtr<nsIFormControl>formControl=do_QueryObject(this);if(!formControl){returnfalse;// Not spellchecked by default}// Is this a multiline plaintext input?int32_tcontrolType=formControl->ControlType();if(controlType==NS_FORM_TEXTAREA){returntrue;// Spellchecked by default}// Is this anything other than an input text?// Other inputs are not spellchecked.if(controlType!=NS_FORM_INPUT_TEXT){returnfalse;// Not spellchecked by default}// Does the user want input text spellchecked by default?// NOTE: Do not reflect a pref value of 0 back to the DOM getter.// The web page should not know if the user has disabled spellchecking.// We'll catch this in the editor itself.int32_tspellcheckLevel=Preferences::GetInt("layout.spellcheckDefault",1);returnspellcheckLevel==2;// "Spellcheck multi- and single-line"}boolnsGenericHTMLElement::InNavQuirksMode(nsIDocument*aDoc){returnaDoc&&aDoc->GetCompatibilityMode()==eCompatibility_NavQuirks;}voidnsGenericHTMLElement::UpdateEditableState(boolaNotify){// XXX Should we do this only when in a document?ContentEditableTristatevalue=GetContentEditableValue();if(value!=eInherit){DoSetEditableFlag(!!value,aNotify);return;}nsStyledElement::UpdateEditableState(aNotify);}EventStatesnsGenericHTMLElement::IntrinsicState()const{EventStatesstate=nsGenericHTMLElementBase::IntrinsicState();if(GetDirectionality()==eDir_RTL){state|=NS_EVENT_STATE_RTL;state&=~NS_EVENT_STATE_LTR;}else{// at least for HTML, directionality is exclusively LTR or RTLNS_ASSERTION(GetDirectionality()==eDir_LTR,"HTML element's directionality must be either RTL or LTR");state|=NS_EVENT_STATE_LTR;state&=~NS_EVENT_STATE_RTL;}returnstate;}uint32_tnsGenericHTMLElement::EditableInclusiveDescendantCount(){boolisEditable=IsInUncomposedDoc()&&HasFlag(NODE_IS_EDITABLE)&&GetContentEditableValue()==eTrue;returnEditableDescendantCount()+isEditable;}nsresultnsGenericHTMLElement::BindToTree(nsIDocument*aDocument,nsIContent*aParent,nsIContent*aBindingParent,boolaCompileEventHandlers){nsresultrv=nsGenericHTMLElementBase::BindToTree(aDocument,aParent,aBindingParent,aCompileEventHandlers);NS_ENSURE_SUCCESS(rv,rv);if(aDocument){RegAccessKey();if(HasName()){aDocument->AddToNameTable(this,GetParsedAttr(nsGkAtoms::name)->GetAtomValue());}if(HasFlag(NODE_IS_EDITABLE)&&GetContentEditableValue()==eTrue){nsCOMPtr<nsIHTMLDocument>htmlDocument=do_QueryInterface(aDocument);if(htmlDocument){htmlDocument->ChangeContentEditableCount(this,+1);}}}// We need to consider a labels element is moved to another subtree// with different root, it needs to update labels list and its root// as well.nsDOMSlots*slots=GetExistingDOMSlots();if(slots&&slots->mLabelsList){slots->mLabelsList->MaybeResetRoot(SubtreeRoot());}returnrv;}voidnsGenericHTMLElement::UnbindFromTree(boolaDeep,boolaNullParent){if(IsInUncomposedDoc()){UnregAccessKey();}RemoveFromNameTable();if(GetContentEditableValue()==eTrue){//XXXsmaug Fix this for Shadow DOM, bug 1066965.nsCOMPtr<nsIHTMLDocument>htmlDocument=do_QueryInterface(GetUncomposedDoc());if(htmlDocument){htmlDocument->ChangeContentEditableCount(this,-1);}}// We need to consider a labels element is removed from tree,// it needs to update labels list and its root as well.nsDOMSlots*slots=GetExistingDOMSlots();if(slots&&slots->mLabelsList){slots->mLabelsList->MaybeResetRoot(SubtreeRoot());}nsStyledElement::UnbindFromTree(aDeep,aNullParent);}HTMLFormElement*nsGenericHTMLElement::FindAncestorForm(HTMLFormElement*aCurrentForm){NS_ASSERTION(!HasAttr(kNameSpaceID_None,nsGkAtoms::form)||IsHTMLElement(nsGkAtoms::img),"FindAncestorForm should not be called if @form is set!");// Make sure we don't end up finding a form that's anonymous from// our point of view.nsIContent*bindingParent=GetBindingParent();nsIContent*content=this;while(content!=bindingParent&&content){// If the current ancestor is a form, return it as our formif(content->IsHTMLElement(nsGkAtoms::form)){#ifdef DEBUGif(!nsContentUtils::IsInSameAnonymousTree(this,content)){// It's possible that we started unbinding at |content| or// some ancestor of it, and |content| and |this| used to all be// anonymous. Check for this the hard way.for(nsIContent*child=this;child!=content;child=child->GetParent()){NS_ASSERTION(child->GetParent()->IndexOf(child)!=-1,"Walked too far?");}}#endifreturnstatic_cast<HTMLFormElement*>(content);}nsIContent*prevContent=content;content=prevContent->GetParent();if(!content&&aCurrentForm){// We got to the root of the subtree we're in, and we're being removed// from the DOM (the only time we get into this method with a non-null// aCurrentForm). Check whether aCurrentForm is in the same subtree. If// it is, we want to return aCurrentForm, since this case means that// we're one of those inputs-in-a-table that have a hacked mForm pointer// and a subtree containing both us and the form got removed from the// DOM.if(nsContentUtils::ContentIsDescendantOf(aCurrentForm,prevContent)){returnaCurrentForm;}}}returnnullptr;}boolnsGenericHTMLElement::CheckHandleEventForAnchorsPreconditions(EventChainVisitor&aVisitor){NS_PRECONDITION(nsCOMPtr<Link>(do_QueryObject(this)),"should be called only when |this| implements |Link|");if(!aVisitor.mPresContext){// We need a pres context to do link stuff. Some events (e.g. mutation// events) don't have one.// XXX: ideally, shouldn't we be able to do what we need without one?returnfalse;}//Need to check if we hit an imagemap area and if so see if we're handling//the event on that map or on a link farther up the tree. If we're on a//link farther up, do nothing.nsCOMPtr<nsIContent>target=aVisitor.mPresContext->EventStateManager()->GetEventTargetContent(aVisitor.mEvent);return!target||!target->IsHTMLElement(nsGkAtoms::area)||IsHTMLElement(nsGkAtoms::area);}nsresultnsGenericHTMLElement::GetEventTargetParentForAnchors(EventChainPreVisitor&aVisitor){nsresultrv=nsGenericHTMLElementBase::GetEventTargetParent(aVisitor);NS_ENSURE_SUCCESS(rv,rv);if(!CheckHandleEventForAnchorsPreconditions(aVisitor)){returnNS_OK;}returnGetEventTargetParentForLinks(aVisitor);}nsresultnsGenericHTMLElement::PostHandleEventForAnchors(EventChainPostVisitor&aVisitor){if(!CheckHandleEventForAnchorsPreconditions(aVisitor)){returnNS_OK;}returnPostHandleEventForLinks(aVisitor);}boolnsGenericHTMLElement::IsHTMLLink(nsIURI**aURI)const{NS_PRECONDITION(aURI,"Must provide aURI out param");*aURI=GetHrefURIForAnchors().take();// We promise out param is non-null if we return true, so base rv on itreturn*aURI!=nullptr;}already_AddRefed<nsIURI>nsGenericHTMLElement::GetHrefURIForAnchors()const{// This is used by the three Link implementations and// nsHTMLStyleElement.// Get href= attribute (relative URI).// We use the nsAttrValue's copy of the URI string to avoid copying.nsCOMPtr<nsIURI>uri;GetURIAttr(nsGkAtoms::href,nullptr,getter_AddRefs(uri));returnuri.forget();}nsresultnsGenericHTMLElement::BeforeSetAttr(int32_taNamespaceID,nsIAtom*aName,constnsAttrValueOrString*aValue,boolaNotify){if(aNamespaceID==kNameSpaceID_None){if(aName==nsGkAtoms::accesskey){// Have to unregister before clearing flag. See UnregAccessKeyUnregAccessKey();if(!aValue){UnsetFlags(NODE_HAS_ACCESSKEY);}}elseif(aName==nsGkAtoms::name){// Have to do this before clearing flag. See RemoveFromNameTableRemoveFromNameTable();if(!aValue||aValue->IsEmpty()){ClearHasName();}}elseif(aName==nsGkAtoms::contenteditable){if(aValue){// Set this before the attribute is set so that any subclass code that// runs before the attribute is set won't think we're missing a// contenteditable attr when we actually have one.SetMayHaveContentEditableAttr();}}if(!aValue&&IsEventAttributeName(aName)){if(EventListenerManager*manager=GetExistingListenerManager()){manager->RemoveEventHandler(aName,EmptyString());}}}returnnsGenericHTMLElementBase::BeforeSetAttr(aNamespaceID,aName,aValue,aNotify);}nsresultnsGenericHTMLElement::AfterSetAttr(int32_taNamespaceID,nsIAtom*aName,constnsAttrValue*aValue,constnsAttrValue*aOldValue,boolaNotify){if(aNamespaceID==kNameSpaceID_None){if(IsEventAttributeName(aName)&&aValue){MOZ_ASSERT(aValue->Type()==nsAttrValue::eString,"Expected string value for script body");nsresultrv=SetEventHandler(aName,aValue->GetStringValue());NS_ENSURE_SUCCESS(rv,rv);}elseif(aNotify&&aName==nsGkAtoms::spellcheck){SyncEditorsOnSubtree(this);}elseif(aName==nsGkAtoms::dir){Directionalitydir=eDir_LTR;// A boolean tracking whether we need to recompute our directionality.// This needs to happen after we update our internal "dir" attribute// state but before we call SetDirectionalityOnDescendants.boolrecomputeDirectionality=false;// We don't want to have to keep getting the "dir" attribute in// IntrinsicState, so we manually recompute our dir-related event states// here and send the relevant update notifications.EventStatesdirStates;if(aValue&&aValue->Type()==nsAttrValue::eEnum){SetHasValidDir();dirStates|=NS_EVENT_STATE_HAS_DIR_ATTR;DirectionalitydirValue=(Directionality)aValue->GetEnumValue();if(dirValue==eDir_Auto){dirStates|=NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO;}else{dir=dirValue;SetDirectionality(dir,aNotify);if(dirValue==eDir_LTR){dirStates|=NS_EVENT_STATE_DIR_ATTR_LTR;}else{MOZ_ASSERT(dirValue==eDir_RTL);dirStates|=NS_EVENT_STATE_DIR_ATTR_RTL;}}}else{if(aValue){// We have a value, just not a valid one.dirStates|=NS_EVENT_STATE_HAS_DIR_ATTR;}ClearHasValidDir();if(NodeInfo()->Equals(nsGkAtoms::bdi)){dirStates|=NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO;}else{recomputeDirectionality=true;}}// Now figure out what's changed about our dir states.EventStatesoldDirStates=State()&DIR_ATTR_STATES;EventStateschangedStates=dirStates^oldDirStates;ToggleStates(changedStates,aNotify);if(recomputeDirectionality){dir=RecomputeDirectionality(this,aNotify);}SetDirectionalityOnDescendants(this,dir,aNotify);}elseif(aName==nsGkAtoms::contenteditable){int32_teditableCountDelta=0;if(aOldValue&&(aOldValue->Equals(NS_LITERAL_STRING("true"),eIgnoreCase)||aOldValue->Equals(EmptyString(),eIgnoreCase))){editableCountDelta=-1;}if(aValue&&(aValue->Equals(NS_LITERAL_STRING("true"),eIgnoreCase)||aValue->Equals(EmptyString(),eIgnoreCase))){++editableCountDelta;}ChangeEditableState(editableCountDelta);}elseif(aName==nsGkAtoms::accesskey){if(aValue&&!aValue->Equals(EmptyString(),eIgnoreCase)){SetFlags(NODE_HAS_ACCESSKEY);RegAccessKey();}}elseif(aName==nsGkAtoms::name){if(aValue&&!aValue->Equals(EmptyString(),eIgnoreCase)&&CanHaveName(NodeInfo()->NameAtom())){// This may not be quite right because we can have subclass code run// before here. But in practice subclasses don't care about this flag,// and in particular selector matching does not care. Otherwise we'd// want to handle it like we handle id attributes (in PreIdMaybeChange// and PostIdMaybeChange).SetHasName();AddToNameTable(aValue->GetAtomValue());}}}returnnsGenericHTMLElementBase::AfterSetAttr(aNamespaceID,aName,aValue,aOldValue,aNotify);}EventListenerManager*nsGenericHTMLElement::GetEventListenerManagerForAttr(nsIAtom*aAttrName,bool*aDefer){// Attributes on the body and frameset tags get set on the global objectif((mNodeInfo->Equals(nsGkAtoms::body)||mNodeInfo->Equals(nsGkAtoms::frameset))&&// We only forward some event attributes from body/frameset to window(0#define EVENT(name_, id_, type_, struct_) /* nothing */#define FORWARDED_EVENT(name_, id_, type_, struct_) \ || nsGkAtoms::on##name_ == aAttrName#define WINDOW_EVENT FORWARDED_EVENT#include"mozilla/EventNameList.h" // IWYU pragma: keep#undef WINDOW_EVENT#undef FORWARDED_EVENT#undef EVENT)){nsPIDOMWindowInner*win;// If we have a document, and it has a window, add the event// listener on the window (the inner window). If not, proceed as// normal.// XXXbz sXBL/XBL2 issue: should we instead use GetComposedDoc() here,// override BindToTree for those classes and munge event listeners there?nsIDocument*document=OwnerDoc();*aDefer=false;if((win=document->GetInnerWindow())){nsCOMPtr<EventTarget>piTarget(do_QueryInterface(win));returnpiTarget->GetOrCreateListenerManager();}returnnullptr;}returnnsGenericHTMLElementBase::GetEventListenerManagerForAttr(aAttrName,aDefer);}#define EVENT(name_, id_, type_, struct_) /* nothing; handled by nsINode */#define FORWARDED_EVENT(name_, id_, type_, struct_) \EventHandlerNonNull* \nsGenericHTMLElement::GetOn##name_() \{ \ if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) { \/* XXXbz note to self: add tests for this! */ \ if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) { \ nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \ return globalWin->GetOn##name_(); \ } \ return nullptr; \ } \ \ return nsINode::GetOn##name_(); \} \void \nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler) \{ \ if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) { \ nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow(); \ if (!win) { \ return; \ } \ \ nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \ return globalWin->SetOn##name_(handler); \ } \ \ return nsINode::SetOn##name_(handler); \}#define ERROR_EVENT(name_, id_, type_, struct_) \already_AddRefed<EventHandlerNonNull> \nsGenericHTMLElement::GetOn##name_() \{ \ if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) { \/* XXXbz note to self: add tests for this! */ \ if (nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow()) { \ nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \ OnErrorEventHandlerNonNull* errorHandler = globalWin->GetOn##name_(); \ if (errorHandler) { \ RefPtr<EventHandlerNonNull> handler = \ new EventHandlerNonNull(errorHandler); \ return handler.forget(); \ } \ } \ return nullptr; \ } \ \ RefPtr<EventHandlerNonNull> handler = nsINode::GetOn##name_(); \ return handler.forget(); \} \void \nsGenericHTMLElement::SetOn##name_(EventHandlerNonNull* handler) \{ \ if (IsAnyOfHTMLElements(nsGkAtoms::body, nsGkAtoms::frameset)) { \ nsPIDOMWindowInner* win = OwnerDoc()->GetInnerWindow(); \ if (!win) { \ return; \ } \ \ nsGlobalWindow* globalWin = nsGlobalWindow::Cast(win); \ RefPtr<OnErrorEventHandlerNonNull> errorHandler; \ if (handler) { \ errorHandler = new OnErrorEventHandlerNonNull(handler); \ } \ return globalWin->SetOn##name_(errorHandler); \ } \ \ return nsINode::SetOn##name_(handler); \}#include"mozilla/EventNameList.h" // IWYU pragma: keep#undef ERROR_EVENT#undef FORWARDED_EVENT#undef EVENTvoidnsGenericHTMLElement::GetBaseTarget(nsAString&aBaseTarget)const{OwnerDoc()->GetBaseTarget(aBaseTarget);}//----------------------------------------------------------------------boolnsGenericHTMLElement::ParseAttribute(int32_taNamespaceID,nsIAtom*aAttribute,constnsAString&aValue,nsAttrValue&aResult){if(aNamespaceID==kNameSpaceID_None){if(aAttribute==nsGkAtoms::dir){returnaResult.ParseEnumValue(aValue,kDirTable,false);}if(aAttribute==nsGkAtoms::tabindex){returnaResult.ParseIntValue(aValue);}if(aAttribute==nsGkAtoms::referrerpolicy){returnParseReferrerAttribute(aValue,aResult);}if(aAttribute==nsGkAtoms::name){// Store name as an atom. name="" means that the element has no name,// not that it has an empty string as the name.if(aValue.IsEmpty()){returnfalse;}aResult.ParseAtom(aValue);returntrue;}if(aAttribute==nsGkAtoms::contenteditable){aResult.ParseAtom(aValue);returntrue;}if(aAttribute==nsGkAtoms::rel){aResult.ParseAtomArray(aValue);returntrue;}}returnnsGenericHTMLElementBase::ParseAttribute(aNamespaceID,aAttribute,aValue,aResult);}boolnsGenericHTMLElement::ParseBackgroundAttribute(int32_taNamespaceID,nsIAtom*aAttribute,constnsAString&aValue,nsAttrValue&aResult){if(aNamespaceID==kNameSpaceID_None&&aAttribute==nsGkAtoms::background&&!aValue.IsEmpty()){// Resolve url to an absolute urlnsIDocument*doc=OwnerDoc();nsCOMPtr<nsIURI>baseURI=GetBaseURI();nsCOMPtr<nsIURI>uri;nsresultrv=nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),aValue,doc,baseURI);if(NS_FAILED(rv)){returnfalse;}mozilla::css::URLValue*url=newmozilla::css::URLValue(uri,aValue,baseURI,doc->GetDocumentURI(),NodePrincipal());aResult.SetTo(url,&aValue);returntrue;}returnfalse;}boolnsGenericHTMLElement::IsAttributeMapped(constnsIAtom*aAttribute)const{staticconstMappedAttributeEntry*constmap[]={sCommonAttributeMap};returnFindAttributeDependence(aAttribute,map);}nsMapRuleToAttributesFuncnsGenericHTMLElement::GetAttributeMappingFunction()const{return&MapCommonAttributesInto;}nsIFormControlFrame*nsGenericHTMLElement::GetFormControlFrame(boolaFlushFrames){if(aFlushFrames&&IsInComposedDoc()){// Cause a flush of the frames, so we get up-to-date frame informationGetComposedDoc()->FlushPendingNotifications(FlushType::Frames);}nsIFrame*frame=GetPrimaryFrame();if(frame){nsIFormControlFrame*form_frame=do_QueryFrame(frame);if(form_frame){returnform_frame;}// If we have generated content, the primary frame will be a// wrapper frame.. out real frame will be in its child list.for(frame=frame->PrincipalChildList().FirstChild();frame;frame=frame->GetNextSibling()){form_frame=do_QueryFrame(frame);if(form_frame){returnform_frame;}}}returnnullptr;}nsPresContext*nsGenericHTMLElement::GetPresContext(PresContextForaFor){// Get the documentnsIDocument*doc=(aFor==eForComposedDoc)?GetComposedDoc():GetUncomposedDoc();if(doc){// Get presentation shell.nsIPresShell*presShell=doc->GetShell();if(presShell){returnpresShell->GetPresContext();}}returnnullptr;}staticconstnsAttrValue::EnumTablekDivAlignTable[]={{"left",NS_STYLE_TEXT_ALIGN_MOZ_LEFT},{"right",NS_STYLE_TEXT_ALIGN_MOZ_RIGHT},{"center",NS_STYLE_TEXT_ALIGN_MOZ_CENTER},{"middle",NS_STYLE_TEXT_ALIGN_MOZ_CENTER},{"justify",NS_STYLE_TEXT_ALIGN_JUSTIFY},{nullptr,0}};staticconstnsAttrValue::EnumTablekFrameborderTable[]={{"yes",NS_STYLE_FRAME_YES},{"no",NS_STYLE_FRAME_NO},{"1",NS_STYLE_FRAME_1},{"0",NS_STYLE_FRAME_0},{nullptr,0}};staticconstnsAttrValue::EnumTablekScrollingTable[]={{"yes",NS_STYLE_FRAME_YES},{"no",NS_STYLE_FRAME_NO},{"on",NS_STYLE_FRAME_ON},{"off",NS_STYLE_FRAME_OFF},{"scroll",NS_STYLE_FRAME_SCROLL},{"noscroll",NS_STYLE_FRAME_NOSCROLL},{"auto",NS_STYLE_FRAME_AUTO},{nullptr,0}};staticconstnsAttrValue::EnumTablekTableVAlignTable[]={{"top",NS_STYLE_VERTICAL_ALIGN_TOP},{"middle",NS_STYLE_VERTICAL_ALIGN_MIDDLE},{"bottom",NS_STYLE_VERTICAL_ALIGN_BOTTOM},{"baseline",NS_STYLE_VERTICAL_ALIGN_BASELINE},{nullptr,0}};boolnsGenericHTMLElement::ParseAlignValue(constnsAString&aString,nsAttrValue&aResult){staticconstnsAttrValue::EnumTablekAlignTable[]={{"left",NS_STYLE_TEXT_ALIGN_LEFT},{"right",NS_STYLE_TEXT_ALIGN_RIGHT},{"top",NS_STYLE_VERTICAL_ALIGN_TOP},{"middle",NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE},{"bottom",NS_STYLE_VERTICAL_ALIGN_BASELINE},{"center",NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE},{"baseline",NS_STYLE_VERTICAL_ALIGN_BASELINE},{"texttop",NS_STYLE_VERTICAL_ALIGN_TEXT_TOP},{"absmiddle",NS_STYLE_VERTICAL_ALIGN_MIDDLE},{"abscenter",NS_STYLE_VERTICAL_ALIGN_MIDDLE},{"absbottom",NS_STYLE_VERTICAL_ALIGN_BOTTOM},{nullptr,0}};returnaResult.ParseEnumValue(aString,kAlignTable,false);}//----------------------------------------staticconstnsAttrValue::EnumTablekTableHAlignTable[]={{"left",NS_STYLE_TEXT_ALIGN_LEFT},{"right",NS_STYLE_TEXT_ALIGN_RIGHT},{"center",NS_STYLE_TEXT_ALIGN_CENTER},{"char",NS_STYLE_TEXT_ALIGN_CHAR},{"justify",NS_STYLE_TEXT_ALIGN_JUSTIFY},{nullptr,0}};boolnsGenericHTMLElement::ParseTableHAlignValue(constnsAString&aString,nsAttrValue&aResult){returnaResult.ParseEnumValue(aString,kTableHAlignTable,false);}//----------------------------------------// This table is used for td, th, tr, col, thead, tbody and tfoot.staticconstnsAttrValue::EnumTablekTableCellHAlignTable[]={{"left",NS_STYLE_TEXT_ALIGN_MOZ_LEFT},{"right",NS_STYLE_TEXT_ALIGN_MOZ_RIGHT},{"center",NS_STYLE_TEXT_ALIGN_MOZ_CENTER},{"char",NS_STYLE_TEXT_ALIGN_CHAR},{"justify",NS_STYLE_TEXT_ALIGN_JUSTIFY},{"middle",NS_STYLE_TEXT_ALIGN_MOZ_CENTER},{"absmiddle",NS_STYLE_TEXT_ALIGN_CENTER},{nullptr,0}};boolnsGenericHTMLElement::ParseTableCellHAlignValue(constnsAString&aString,nsAttrValue&aResult){returnaResult.ParseEnumValue(aString,kTableCellHAlignTable,false);}//----------------------------------------boolnsGenericHTMLElement::ParseTableVAlignValue(constnsAString&aString,nsAttrValue&aResult){returnaResult.ParseEnumValue(aString,kTableVAlignTable,false);}boolnsGenericHTMLElement::ParseDivAlignValue(constnsAString&aString,nsAttrValue&aResult){returnaResult.ParseEnumValue(aString,kDivAlignTable,false);}boolnsGenericHTMLElement::ParseImageAttribute(nsIAtom*aAttribute,constnsAString&aString,nsAttrValue&aResult){if((aAttribute==nsGkAtoms::width)||(aAttribute==nsGkAtoms::height)){returnaResult.ParseSpecialIntValue(aString);}if((aAttribute==nsGkAtoms::hspace)||(aAttribute==nsGkAtoms::vspace)||(aAttribute==nsGkAtoms::border)){returnaResult.ParseIntWithBounds(aString,0);}returnfalse;}boolnsGenericHTMLElement::ParseReferrerAttribute(constnsAString&aString,nsAttrValue&aResult){staticconstnsAttrValue::EnumTablekReferrerTable[]={{net::kRPS_No_Referrer,static_cast<int16_t>(net::RP_No_Referrer)},{net::kRPS_Origin,static_cast<int16_t>(net::RP_Origin)},{net::kRPS_Origin_When_Cross_Origin,static_cast<int16_t>(net::RP_Origin_When_Crossorigin)},{net::kRPS_No_Referrer_When_Downgrade,static_cast<int16_t>(net::RP_No_Referrer_When_Downgrade)},{net::kRPS_Unsafe_URL,static_cast<int16_t>(net::RP_Unsafe_URL)},{net::kRPS_Strict_Origin,static_cast<int16_t>(net::RP_Strict_Origin)},{net::kRPS_Same_Origin,static_cast<int16_t>(net::RP_Same_Origin)},{net::kRPS_Strict_Origin_When_Cross_Origin,static_cast<int16_t>(net::RP_Strict_Origin_When_Cross_Origin)},{nullptr,0}};returnaResult.ParseEnumValue(aString,kReferrerTable,false);}boolnsGenericHTMLElement::ParseFrameborderValue(constnsAString&aString,nsAttrValue&aResult){returnaResult.ParseEnumValue(aString,kFrameborderTable,false);}boolnsGenericHTMLElement::ParseScrollingValue(constnsAString&aString,nsAttrValue&aResult){returnaResult.ParseEnumValue(aString,kScrollingTable,false);}staticinlinevoidMapLangAttributeInto(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){if(!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Font)|NS_STYLE_INHERIT_BIT(Text))){return;}constnsAttrValue*langValue=aAttributes->GetAttr(nsGkAtoms::lang);if(!langValue){return;}MOZ_ASSERT(langValue->Type()==nsAttrValue::eAtom);if(aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Font))){aData->SetIdentAtomValueIfUnset(eCSSProperty__x_lang,langValue->GetAtomValue());}if(aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Text))){if(!aData->PropertyIsSet(eCSSProperty_text_emphasis_position)){constnsIAtom*lang=langValue->GetAtomValue();if(nsStyleUtil::MatchesLanguagePrefix(lang,u"zh")){aData->SetKeywordValue(eCSSProperty_text_emphasis_position,NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT_ZH);}elseif(nsStyleUtil::MatchesLanguagePrefix(lang,u"ja")||nsStyleUtil::MatchesLanguagePrefix(lang,u"mn")){// This branch is currently no part of the spec.// See bug 1040668 comment 69 and comment 75.aData->SetKeywordValue(eCSSProperty_text_emphasis_position,NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT);}}}}/** * Handle attributes common to all html elements */voidnsGenericHTMLElement::MapCommonAttributesIntoExceptHidden(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){if(aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(UserInterface))){if(!aData->PropertyIsSet(eCSSProperty__moz_user_modify)){constnsAttrValue*value=aAttributes->GetAttr(nsGkAtoms::contenteditable);if(value){if(value->Equals(nsGkAtoms::_empty,eCaseMatters)||value->Equals(nsGkAtoms::_true,eIgnoreCase)){aData->SetKeywordValue(eCSSProperty__moz_user_modify,StyleUserModify::ReadWrite);}elseif(value->Equals(nsGkAtoms::_false,eIgnoreCase)){aData->SetKeywordValue(eCSSProperty__moz_user_modify,StyleUserModify::ReadOnly);}}}}MapLangAttributeInto(aAttributes,aData);}voidnsGenericHTMLElement::MapCommonAttributesInto(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){MapCommonAttributesIntoExceptHidden(aAttributes,aData);if(aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Display))){if(!aData->PropertyIsSet(eCSSProperty_display)){if(aAttributes->IndexOfAttr(nsGkAtoms::hidden)>=0){aData->SetKeywordValue(eCSSProperty_display,StyleDisplay::None);}}}}/* static */constnsGenericHTMLElement::MappedAttributeEntrynsGenericHTMLElement::sCommonAttributeMap[]={{&nsGkAtoms::contenteditable},{&nsGkAtoms::lang},{&nsGkAtoms::hidden},{nullptr}};/* static */constElement::MappedAttributeEntrynsGenericHTMLElement::sImageMarginSizeAttributeMap[]={{&nsGkAtoms::width},{&nsGkAtoms::height},{&nsGkAtoms::hspace},{&nsGkAtoms::vspace},{nullptr}};/* static */constElement::MappedAttributeEntrynsGenericHTMLElement::sImageAlignAttributeMap[]={{&nsGkAtoms::align},{nullptr}};/* static */constElement::MappedAttributeEntrynsGenericHTMLElement::sDivAlignAttributeMap[]={{&nsGkAtoms::align},{nullptr}};/* static */constElement::MappedAttributeEntrynsGenericHTMLElement::sImageBorderAttributeMap[]={{&nsGkAtoms::border},{nullptr}};/* static */constElement::MappedAttributeEntrynsGenericHTMLElement::sBackgroundAttributeMap[]={{&nsGkAtoms::background},{&nsGkAtoms::bgcolor},{nullptr}};/* static */constElement::MappedAttributeEntrynsGenericHTMLElement::sBackgroundColorAttributeMap[]={{&nsGkAtoms::bgcolor},{nullptr}};voidnsGenericHTMLElement::MapImageAlignAttributeInto(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){if(aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Display))){constnsAttrValue*value=aAttributes->GetAttr(nsGkAtoms::align);if(value&&value->Type()==nsAttrValue::eEnum){int32_talign=value->GetEnumValue();if(!aData->PropertyIsSet(eCSSProperty_float_)){if(align==NS_STYLE_TEXT_ALIGN_LEFT){aData->SetKeywordValue(eCSSProperty_float_,StyleFloat::Left);}elseif(align==NS_STYLE_TEXT_ALIGN_RIGHT){aData->SetKeywordValue(eCSSProperty_float_,StyleFloat::Right);}}if(!aData->PropertyIsSet(eCSSProperty_vertical_align)){switch(align){caseNS_STYLE_TEXT_ALIGN_LEFT:caseNS_STYLE_TEXT_ALIGN_RIGHT:break;default:aData->SetKeywordValue(eCSSProperty_vertical_align,align);break;}}}}}voidnsGenericHTMLElement::MapDivAlignAttributeInto(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){if(aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Text))){if(!aData->PropertyIsSet(eCSSProperty_text_align)){// align: enumconstnsAttrValue*value=aAttributes->GetAttr(nsGkAtoms::align);if(value&&value->Type()==nsAttrValue::eEnum)aData->SetKeywordValue(eCSSProperty_text_align,value->GetEnumValue());}}}voidnsGenericHTMLElement::MapVAlignAttributeInto(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){if(aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Display))){if(!aData->PropertyIsSet(eCSSProperty_vertical_align)){// align: enumconstnsAttrValue*value=aAttributes->GetAttr(nsGkAtoms::valign);if(value&&value->Type()==nsAttrValue::eEnum)aData->SetKeywordValue(eCSSProperty_vertical_align,value->GetEnumValue());}}}voidnsGenericHTMLElement::MapImageMarginAttributeInto(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){if(!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Margin)))return;constnsAttrValue*value;// hspace: valuevalue=aAttributes->GetAttr(nsGkAtoms::hspace);if(value){if(value->Type()==nsAttrValue::eInteger){aData->SetPixelValueIfUnset(eCSSProperty_margin_left,(float)value->GetIntegerValue());aData->SetPixelValueIfUnset(eCSSProperty_margin_right,(float)value->GetIntegerValue());}elseif(value->Type()==nsAttrValue::ePercent){aData->SetPercentValueIfUnset(eCSSProperty_margin_left,value->GetPercentValue());aData->SetPercentValueIfUnset(eCSSProperty_margin_right,value->GetPercentValue());}}// vspace: valuevalue=aAttributes->GetAttr(nsGkAtoms::vspace);if(value){if(value->Type()==nsAttrValue::eInteger){aData->SetPixelValueIfUnset(eCSSProperty_margin_top,(float)value->GetIntegerValue());aData->SetPixelValueIfUnset(eCSSProperty_margin_bottom,(float)value->GetIntegerValue());}elseif(value->Type()==nsAttrValue::ePercent){aData->SetPercentValueIfUnset(eCSSProperty_margin_top,value->GetPercentValue());aData->SetPercentValueIfUnset(eCSSProperty_margin_bottom,value->GetPercentValue());}}}voidnsGenericHTMLElement::MapWidthAttributeInto(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){if(!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Position))){return;}// width: valueif(!aData->PropertyIsSet(eCSSProperty_width)){constnsAttrValue*value=aAttributes->GetAttr(nsGkAtoms::width);if(value&&value->Type()==nsAttrValue::eInteger){aData->SetPixelValue(eCSSProperty_width,(float)value->GetIntegerValue());}elseif(value&&value->Type()==nsAttrValue::ePercent){aData->SetPercentValue(eCSSProperty_width,value->GetPercentValue());}}}voidnsGenericHTMLElement::MapHeightAttributeInto(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){if(!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Position)))return;// height: valueif(!aData->PropertyIsSet(eCSSProperty_height)){constnsAttrValue*value=aAttributes->GetAttr(nsGkAtoms::height);if(value&&value->Type()==nsAttrValue::eInteger){aData->SetPixelValue(eCSSProperty_height,(float)value->GetIntegerValue());}elseif(value&&value->Type()==nsAttrValue::ePercent){aData->SetPercentValue(eCSSProperty_height,value->GetPercentValue());}}}voidnsGenericHTMLElement::MapImageSizeAttributesInto(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){nsGenericHTMLElement::MapWidthAttributeInto(aAttributes,aData);nsGenericHTMLElement::MapHeightAttributeInto(aAttributes,aData);}voidnsGenericHTMLElement::MapImageBorderAttributeInto(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){if(!(aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Border))))return;// border: pixelsconstnsAttrValue*value=aAttributes->GetAttr(nsGkAtoms::border);if(!value)return;nscoordval=0;if(value->Type()==nsAttrValue::eInteger)val=value->GetIntegerValue();aData->SetPixelValueIfUnset(eCSSProperty_border_top_width,(float)val);aData->SetPixelValueIfUnset(eCSSProperty_border_right_width,(float)val);aData->SetPixelValueIfUnset(eCSSProperty_border_bottom_width,(float)val);aData->SetPixelValueIfUnset(eCSSProperty_border_left_width,(float)val);aData->SetKeywordValueIfUnset(eCSSProperty_border_top_style,NS_STYLE_BORDER_STYLE_SOLID);aData->SetKeywordValueIfUnset(eCSSProperty_border_right_style,NS_STYLE_BORDER_STYLE_SOLID);aData->SetKeywordValueIfUnset(eCSSProperty_border_bottom_style,NS_STYLE_BORDER_STYLE_SOLID);aData->SetKeywordValueIfUnset(eCSSProperty_border_left_style,NS_STYLE_BORDER_STYLE_SOLID);aData->SetCurrentColorIfUnset(eCSSProperty_border_top_color);aData->SetCurrentColorIfUnset(eCSSProperty_border_right_color);aData->SetCurrentColorIfUnset(eCSSProperty_border_bottom_color);aData->SetCurrentColorIfUnset(eCSSProperty_border_left_color);}voidnsGenericHTMLElement::MapBackgroundInto(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){if(!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Background)))return;if(!aData->PropertyIsSet(eCSSProperty_background_image)&&aData->PresContext()->UseDocumentColors()){// backgroundnsAttrValue*value=const_cast<nsAttrValue*>(aAttributes->GetAttr(nsGkAtoms::background));if(value){aData->SetBackgroundImage(*value);}}}voidnsGenericHTMLElement::MapBGColorInto(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){if(!aData->ShouldComputeStyleStruct(NS_STYLE_INHERIT_BIT(Background)))return;if(!aData->PropertyIsSet(eCSSProperty_background_color)&&aData->PresContext()->UseDocumentColors()){constnsAttrValue*value=aAttributes->GetAttr(nsGkAtoms::bgcolor);nscolorcolor;if(value&&value->GetColorValue(color)){aData->SetColorValue(eCSSProperty_background_color,color);}}}voidnsGenericHTMLElement::MapBackgroundAttributesInto(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){MapBackgroundInto(aAttributes,aData);MapBGColorInto(aAttributes,aData);}//----------------------------------------------------------------------nsresultnsGenericHTMLElement::SetAttrHelper(nsIAtom*aAttr,constnsAString&aValue){returnSetAttr(kNameSpaceID_None,aAttr,aValue,true);}int32_tnsGenericHTMLElement::GetIntAttr(nsIAtom*aAttr,int32_taDefault)const{constnsAttrValue*attrVal=mAttrsAndChildren.GetAttr(aAttr);if(attrVal&&attrVal->Type()==nsAttrValue::eInteger){returnattrVal->GetIntegerValue();}returnaDefault;}nsresultnsGenericHTMLElement::SetIntAttr(nsIAtom*aAttr,int32_taValue){nsAutoStringvalue;value.AppendInt(aValue);returnSetAttr(kNameSpaceID_None,aAttr,value,true);}uint32_tnsGenericHTMLElement::GetUnsignedIntAttr(nsIAtom*aAttr,uint32_taDefault)const{constnsAttrValue*attrVal=mAttrsAndChildren.GetAttr(aAttr);if(!attrVal||attrVal->Type()!=nsAttrValue::eInteger){returnaDefault;}returnattrVal->GetIntegerValue();}voidnsGenericHTMLElement::GetURIAttr(nsIAtom*aAttr,nsIAtom*aBaseAttr,nsAString&aResult)const{nsCOMPtr<nsIURI>uri;boolhadAttr=GetURIAttr(aAttr,aBaseAttr,getter_AddRefs(uri));if(!hadAttr){aResult.Truncate();return;}if(!uri){// Just return the attr valueGetAttr(kNameSpaceID_None,aAttr,aResult);return;}nsAutoCStringspec;uri->GetSpec(spec);CopyUTF8toUTF16(spec,aResult);}boolnsGenericHTMLElement::GetURIAttr(nsIAtom*aAttr,nsIAtom*aBaseAttr,nsIURI**aURI)const{*aURI=nullptr;constnsAttrValue*attr=mAttrsAndChildren.GetAttr(aAttr);if(!attr){returnfalse;}nsCOMPtr<nsIURI>baseURI=GetBaseURI();if(aBaseAttr){nsAutoStringbaseAttrValue;if(GetAttr(kNameSpaceID_None,aBaseAttr,baseAttrValue)){nsCOMPtr<nsIURI>baseAttrURI;nsresultrv=nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(baseAttrURI),baseAttrValue,OwnerDoc(),baseURI);if(NS_FAILED(rv)){returntrue;}baseURI.swap(baseAttrURI);}}// Don't care about return value. If it fails, we still want to// return true, and *aURI will be null.nsContentUtils::NewURIWithDocumentCharset(aURI,attr->GetStringValue(),OwnerDoc(),baseURI);returntrue;}/* static */boolnsGenericHTMLElement::IsScrollGrabAllowed(JSContext*,JSObject*){// Only allow scroll grabbing in chromensIPrincipal*prin=nsContentUtils::SubjectPrincipal();returnnsContentUtils::IsSystemPrincipal(prin);}HTMLMenuElement*nsGenericHTMLElement::GetContextMenu()const{nsAutoStringvalue;GetHTMLAttr(nsGkAtoms::contextmenu,value);if(!value.IsEmpty()){//XXXsmaug How should this work in Shadow DOM?nsIDocument*doc=GetUncomposedDoc();if(doc){returnHTMLMenuElement::FromContentOrNull(doc->GetElementById(value));}}returnnullptr;}NS_IMETHODIMPnsGenericHTMLElement::GetContextMenu(nsIDOMHTMLMenuElement**aContextMenu){NS_IF_ADDREF(*aContextMenu=GetContextMenu());returnNS_OK;}boolnsGenericHTMLElement::IsLabelable()const{returnIsAnyOfHTMLElements(nsGkAtoms::progress,nsGkAtoms::meter);}/* static */boolnsGenericHTMLElement::MatchLabelsElement(Element*aElement,int32_taNamespaceID,nsIAtom*aAtom,void*aData){HTMLLabelElement*element=HTMLLabelElement::FromContent(aElement);returnelement&&element->GetControl()==aData;}already_AddRefed<nsINodeList>nsGenericHTMLElement::Labels(){MOZ_ASSERT(IsLabelable(),"Labels() only allow labelable elements to use it.");nsDOMSlots*slots=DOMSlots();if(!slots->mLabelsList){slots->mLabelsList=newnsLabelsNodeList(SubtreeRoot(),MatchLabelsElement,nullptr,this);}RefPtr<nsLabelsNodeList>labels=slots->mLabelsList;returnlabels.forget();}boolnsGenericHTMLElement::IsInteractiveHTMLContent(boolaIgnoreTabindex)const{returnIsAnyOfHTMLElements(nsGkAtoms::details,nsGkAtoms::embed,nsGkAtoms::keygen)||(!aIgnoreTabindex&&HasAttr(kNameSpaceID_None,nsGkAtoms::tabindex));}// staticboolnsGenericHTMLElement::TouchEventsEnabled(JSContext*aCx,JSObject*aGlobal){returnTouchEvent::PrefEnabled(aCx,aGlobal);}//----------------------------------------------------------------------nsGenericHTMLFormElement::nsGenericHTMLFormElement(already_AddRefed<mozilla::dom::NodeInfo>&aNodeInfo,uint8_taType):nsGenericHTMLElement(aNodeInfo),nsIFormControl(aType),mForm(nullptr),mFieldSet(nullptr){// We should add the NS_EVENT_STATE_ENABLED bit here as needed, but// that depends on our type, which is not initialized yet. So we// have to do this in subclasses.}nsGenericHTMLFormElement::~nsGenericHTMLFormElement(){if(mFieldSet){mFieldSet->RemoveElement(this);}// Check that this element doesn't know anything about its form at this point.NS_ASSERTION(!mForm,"mForm should be null at this point!");}NS_IMPL_ISUPPORTS_INHERITED(nsGenericHTMLFormElement,nsGenericHTMLElement,nsIFormControl)nsINode*nsGenericHTMLFormElement::GetScopeChainParent()const{returnmForm?mForm:nsGenericHTMLElement::GetScopeChainParent();}boolnsGenericHTMLFormElement::IsNodeOfType(uint32_taFlags)const{return!(aFlags&~(eCONTENT|eHTML_FORM_CONTROL));}voidnsGenericHTMLFormElement::SaveSubtreeState(){SaveState();nsGenericHTMLElement::SaveSubtreeState();}voidnsGenericHTMLFormElement::SetForm(nsIDOMHTMLFormElement*aForm){NS_PRECONDITION(aForm,"Don't pass null here");NS_ASSERTION(!mForm,"We don't support switching from one non-null form to another.");SetForm(static_cast<HTMLFormElement*>(aForm),false);}voidnsGenericHTMLFormElement::SetForm(HTMLFormElement*aForm,boolaBindToTree){if(aForm){BeforeSetForm(aBindToTree);}// keep a *weak* ref to the form heremForm=aForm;}voidnsGenericHTMLFormElement::ClearForm(boolaRemoveFromForm,boolaUnbindOrDelete){NS_ASSERTION((mForm!=nullptr)==HasFlag(ADDED_TO_FORM),"Form control should have had flag set correctly");if(!mForm){return;}if(aRemoveFromForm){nsAutoStringnameVal,idVal;GetAttr(kNameSpaceID_None,nsGkAtoms::name,nameVal);GetAttr(kNameSpaceID_None,nsGkAtoms::id,idVal);mForm->RemoveElement(this,true);if(!nameVal.IsEmpty()){mForm->RemoveElementFromTable(this,nameVal);}if(!idVal.IsEmpty()){mForm->RemoveElementFromTable(this,idVal);}}UnsetFlags(ADDED_TO_FORM);mForm=nullptr;AfterClearForm(aUnbindOrDelete);}Element*nsGenericHTMLFormElement::GetFormElement(){returnmForm;}HTMLFieldSetElement*nsGenericHTMLFormElement::GetFieldSet(){returnmFieldSet;}nsresultnsGenericHTMLFormElement::GetForm(nsIDOMHTMLFormElement**aForm){NS_ENSURE_ARG_POINTER(aForm);NS_IF_ADDREF(*aForm=mForm);returnNS_OK;}nsIContent::IMEStatensGenericHTMLFormElement::GetDesiredIMEState(){TextEditor*textEditor=GetTextEditorInternal();if(!textEditor){returnnsGenericHTMLElement::GetDesiredIMEState();}IMEStatestate;nsresultrv=textEditor->GetPreferredIMEState(&state);if(NS_FAILED(rv)){returnnsGenericHTMLElement::GetDesiredIMEState();}returnstate;}nsresultnsGenericHTMLFormElement::BindToTree(nsIDocument*aDocument,nsIContent*aParent,nsIContent*aBindingParent,boolaCompileEventHandlers){nsresultrv=nsGenericHTMLElement::BindToTree(aDocument,aParent,aBindingParent,aCompileEventHandlers);NS_ENSURE_SUCCESS(rv,rv);// An autofocus event has to be launched if the autofocus attribute is// specified and the element accept the autofocus attribute. In addition,// the document should not be already loaded and the "browser.autofocus"// preference should be 'true'.if(IsAutofocusable()&&HasAttr(kNameSpaceID_None,nsGkAtoms::autofocus)&&Preferences::GetBool("browser.autofocus",true)){nsCOMPtr<nsIRunnable>event=newnsAutoFocusEvent(this);rv=NS_DispatchToCurrentThread(event);NS_ENSURE_SUCCESS(rv,rv);}// If @form is set, the element *has* to be in a document, otherwise it// wouldn't be possible to find an element with the corresponding id.// If @form isn't set, the element *has* to have a parent, otherwise it// wouldn't be possible to find a form ancestor.// We should not call UpdateFormOwner if none of these conditions are// fulfilled.if(HasAttr(kNameSpaceID_None,nsGkAtoms::form)?!!GetUncomposedDoc():!!aParent){UpdateFormOwner(true,nullptr);}// Set parent fieldset which should be used for the disabled state.UpdateFieldSet(false);returnNS_OK;}voidnsGenericHTMLFormElement::UnbindFromTree(boolaDeep,boolaNullParent){// Save state before doing anythingSaveState();if(mForm){// Might need to unset mFormif(aNullParent){// No more parent means no more formClearForm(true,true);}else{// Recheck whether we should still have an mForm.if(HasAttr(kNameSpaceID_None,nsGkAtoms::form)||!FindAncestorForm(mForm)){ClearForm(true,true);}else{UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);}}if(!mForm){// Our novalidate state might have changedUpdateState(false);}}// We have to remove the form id observer if there was one.// We will re-add one later if needed (during bind to tree).if(nsContentUtils::HasNonEmptyAttr(this,kNameSpaceID_None,nsGkAtoms::form)){RemoveFormIdObserver();}nsGenericHTMLElement::UnbindFromTree(aDeep,aNullParent);// The element might not have a fieldset anymore.UpdateFieldSet(false);}nsresultnsGenericHTMLFormElement::BeforeSetAttr(int32_taNameSpaceID,nsIAtom*aName,constnsAttrValueOrString*aValue,boolaNotify){if(aNameSpaceID==kNameSpaceID_None){nsAutoStringtmp;// remove the control from the hashtable as neededif(mForm&&(aName==nsGkAtoms::name||aName==nsGkAtoms::id)){GetAttr(kNameSpaceID_None,aName,tmp);if(!tmp.IsEmpty()){mForm->RemoveElementFromTable(this,tmp);}}if(mForm&&aName==nsGkAtoms::type){GetAttr(kNameSpaceID_None,nsGkAtoms::name,tmp);if(!tmp.IsEmpty()){mForm->RemoveElementFromTable(this,tmp);}GetAttr(kNameSpaceID_None,nsGkAtoms::id,tmp);if(!tmp.IsEmpty()){mForm->RemoveElementFromTable(this,tmp);}mForm->RemoveElement(this,false);}if(aName==nsGkAtoms::form){// If @form isn't set or set to the empty string, there were no observer// so we don't have to remove it.if(nsContentUtils::HasNonEmptyAttr(this,kNameSpaceID_None,nsGkAtoms::form)){// The current form id observer is no longer needed.// A new one may be added in AfterSetAttr.RemoveFormIdObserver();}}}returnnsGenericHTMLElement::BeforeSetAttr(aNameSpaceID,aName,aValue,aNotify);}nsresultnsGenericHTMLFormElement::AfterSetAttr(int32_taNameSpaceID,nsIAtom*aName,constnsAttrValue*aValue,constnsAttrValue*aOldValue,boolaNotify){if(aNameSpaceID==kNameSpaceID_None){// add the control to the hashtable as neededif(mForm&&(aName==nsGkAtoms::name||aName==nsGkAtoms::id)&&aValue&&!aValue->IsEmptyString()){MOZ_ASSERT(aValue->Type()==nsAttrValue::eAtom,"Expected atom value for name/id");mForm->AddElementToTable(this,nsDependentAtomString(aValue->GetAtomValue()));}if(mForm&&aName==nsGkAtoms::type){nsAutoStringtmp;GetAttr(kNameSpaceID_None,nsGkAtoms::name,tmp);if(!tmp.IsEmpty()){mForm->AddElementToTable(this,tmp);}GetAttr(kNameSpaceID_None,nsGkAtoms::id,tmp);if(!tmp.IsEmpty()){mForm->AddElementToTable(this,tmp);}mForm->AddElement(this,false,aNotify);}if(aName==nsGkAtoms::form){// We need a new form id observer.//XXXsmaug How should this work in Shadow DOM?nsIDocument*doc=GetUncomposedDoc();if(doc){Element*formIdElement=nullptr;if(aValue&&!aValue->IsEmptyString()){formIdElement=AddFormIdObserver();}// Because we have a new @form value (or no more @form), we have to// update our form owner.UpdateFormOwner(false,formIdElement);}}}returnnsGenericHTMLElement::AfterSetAttr(aNameSpaceID,aName,aValue,aOldValue,aNotify);}nsresultnsGenericHTMLFormElement::GetEventTargetParent(EventChainPreVisitor&aVisitor){if(aVisitor.mEvent->IsTrusted()&&(aVisitor.mEvent->mMessage==eFocus||aVisitor.mEvent->mMessage==eBlur)){// We have to handle focus/blur event to change focus states in// PreHandleEvent to prevent it breaks event target chain creation.aVisitor.mWantsPreHandleEvent=true;}returnnsGenericHTMLElement::GetEventTargetParent(aVisitor);}nsresultnsGenericHTMLFormElement::PreHandleEvent(EventChainVisitor&aVisitor){if(aVisitor.mEvent->IsTrusted()){switch(aVisitor.mEvent->mMessage){caseeFocus:{// Check to see if focus has bubbled up from a form control's// child textfield or button. If that's the case, don't focus// this parent file control -- leave focus on the child.nsIFormControlFrame*formControlFrame=GetFormControlFrame(true);if(formControlFrame&&aVisitor.mEvent->mOriginalTarget==static_cast<nsINode*>(this))formControlFrame->SetFocus(true,true);break;}caseeBlur:{nsIFormControlFrame*formControlFrame=GetFormControlFrame(true);if(formControlFrame)formControlFrame->SetFocus(false,false);break;}default:break;}}returnnsGenericHTMLElement::PreHandleEvent(aVisitor);}/* virtual */boolnsGenericHTMLFormElement::IsDisabled()const{returnHasAttr(kNameSpaceID_None,nsGkAtoms::disabled)||(mFieldSet&&mFieldSet->IsDisabled());}voidnsGenericHTMLFormElement::ForgetFieldSet(nsIContent*aFieldset){if(mFieldSet==aFieldset){mFieldSet=nullptr;}}boolnsGenericHTMLFormElement::CanBeDisabled()const{int32_ttype=ControlType();// It's easier to test the types that _cannot_ be disabledreturntype!=NS_FORM_OBJECT&&type!=NS_FORM_OUTPUT;}boolnsGenericHTMLFormElement::IsHTMLFocusable(boolaWithMouse,bool*aIsFocusable,int32_t*aTabIndex){if(nsGenericHTMLElement::IsHTMLFocusable(aWithMouse,aIsFocusable,aTabIndex)){returntrue;}#ifdef XP_MACOSX*aIsFocusable=(!aWithMouse||nsFocusManager::sMouseFocusesFormControl)&&*aIsFocusable;#endifreturnfalse;}EventStatesnsGenericHTMLFormElement::IntrinsicState()const{// If you add attribute-dependent states here, you need to add them them to// AfterSetAttr too. And add them to AfterSetAttr for all subclasses that// implement IntrinsicState() and are affected by that attribute.EventStatesstate=nsGenericHTMLElement::IntrinsicState();if(CanBeDisabled()){// :enabled/:disabledif(IsDisabled()){state|=NS_EVENT_STATE_DISABLED;state&=~NS_EVENT_STATE_ENABLED;}else{state&=~NS_EVENT_STATE_DISABLED;state|=NS_EVENT_STATE_ENABLED;}}if(mForm&&mForm->IsDefaultSubmitElement(this)){NS_ASSERTION(IsSubmitControl(),"Default submit element that isn't a submit control.");// We are the default submit element (:default)state|=NS_EVENT_STATE_DEFAULT;}// Make the text controls read-writeif(!state.HasState(NS_EVENT_STATE_MOZ_READWRITE)&&IsTextOrNumberControl(/*aExcludePassword*/false)){boolroState=GetBoolAttr(nsGkAtoms::readonly);if(!roState){state|=NS_EVENT_STATE_MOZ_READWRITE;state&=~NS_EVENT_STATE_MOZ_READONLY;}}returnstate;}nsGenericHTMLFormElement::FocusTristatensGenericHTMLFormElement::FocusState(){// We can't be focused if we aren't in a (composed) documentnsIDocument*doc=GetComposedDoc();if(!doc)returneUnfocusable;// first see if we are disabled or not. If disabled then do nothing.if(IsDisabled()){returneUnfocusable;}// If the window is not active, do not allow the focus to bring the// window to the front. We update the focus controller, but do// nothing else.if(nsPIDOMWindowOuter*win=doc->GetWindow()){nsCOMPtr<nsPIDOMWindowOuter>rootWindow=win->GetPrivateRoot();nsCOMPtr<nsIFocusManager>fm=do_GetService(FOCUSMANAGER_CONTRACTID);if(fm&&rootWindow){nsCOMPtr<mozIDOMWindowProxy>activeWindow;fm->GetActiveWindow(getter_AddRefs(activeWindow));if(activeWindow==rootWindow){returneActiveWindow;}}}returneInactiveWindow;}Element*nsGenericHTMLFormElement::AddFormIdObserver(){NS_ASSERTION(GetUncomposedDoc(),"When adding a form id observer, ""we should be in a document!");nsAutoStringformId;nsIDocument*doc=OwnerDoc();GetAttr(kNameSpaceID_None,nsGkAtoms::form,formId);NS_ASSERTION(!formId.IsEmpty(),"@form value should not be the empty string!");nsCOMPtr<nsIAtom>atom=NS_Atomize(formId);returndoc->AddIDTargetObserver(atom,FormIdUpdated,this,false);}voidnsGenericHTMLFormElement::RemoveFormIdObserver(){/** * We are using OwnerDoc() because we don't really care about having the * element actually being in the tree. If it is not and @form value changes, * this method will be called for nothing but removing an observer which does * not exist doesn't cost so much (no entry in the hash table) so having a * boolean for GetUncomposedDoc()/GetOwnerDoc() would make everything look * more complex for nothing. */nsIDocument*doc=OwnerDoc();// At this point, we may not have a document anymore. In that case, we can't// remove the observer. The document did that for us.if(!doc){return;}nsAutoStringformId;GetAttr(kNameSpaceID_None,nsGkAtoms::form,formId);NS_ASSERTION(!formId.IsEmpty(),"@form value should not be the empty string!");nsCOMPtr<nsIAtom>atom=NS_Atomize(formId);doc->RemoveIDTargetObserver(atom,FormIdUpdated,this,false);}/* static */boolnsGenericHTMLFormElement::FormIdUpdated(Element*aOldElement,Element*aNewElement,void*aData){nsGenericHTMLFormElement*element=static_cast<nsGenericHTMLFormElement*>(aData);NS_ASSERTION(element->IsHTMLElement(),"aData should be an HTML element");element->UpdateFormOwner(false,aNewElement);returntrue;}boolnsGenericHTMLFormElement::IsElementDisabledForEvents(EventMessageaMessage,nsIFrame*aFrame){switch(aMessage){caseeMouseMove:caseeMouseOver:caseeMouseOut:caseeMouseEnter:caseeMouseLeave:caseePointerMove:caseePointerOver:caseePointerOut:caseePointerEnter:caseePointerLeave:caseeWheel:caseeLegacyMouseLineOrPageScroll:caseeLegacyMousePixelScroll:returnfalse;default:break;}booldisabled=IsDisabled();if(!disabled&&aFrame){constnsStyleUserInterface*uiStyle=aFrame->StyleUserInterface();disabled=uiStyle->mUserInput==StyleUserInput::None||uiStyle->mUserInput==StyleUserInput::Disabled;}returndisabled;}voidnsGenericHTMLFormElement::UpdateFormOwner(boolaBindToTree,Element*aFormIdElement){NS_PRECONDITION(!aBindToTree||!aFormIdElement,"aFormIdElement shouldn't be set if aBindToTree is true!");boolneedStateUpdate=false;if(!aBindToTree){needStateUpdate=mForm&&mForm->IsDefaultSubmitElement(this);ClearForm(true,false);}HTMLFormElement*oldForm=mForm;if(!mForm){// If @form is set, we have to use that to find the form.nsAutoStringformId;if(GetAttr(kNameSpaceID_None,nsGkAtoms::form,formId)){if(!formId.IsEmpty()){Element*element=nullptr;if(aBindToTree){element=AddFormIdObserver();}else{element=aFormIdElement;}NS_ASSERTION(GetUncomposedDoc(),"The element should be in a document ""when UpdateFormOwner is called!");NS_ASSERTION(!GetUncomposedDoc()||element==GetUncomposedDoc()->GetElementById(formId),"element should be equals to the current element ""associated with the id in @form!");if(element&&element->IsHTMLElement(nsGkAtoms::form)){SetForm(static_cast<HTMLFormElement*>(element),aBindToTree);}}}else{// We now have a parent, so we may have picked up an ancestor form. Search// for it. Note that if mForm is already set we don't want to do this,// because that means someone (probably the content sink) has already set// it to the right value. Also note that even if being bound here didn't// change our parent, we still need to search, since our parent chain// probably changed _somewhere_.SetForm(FindAncestorForm(),aBindToTree);}}if(mForm&&!HasFlag(ADDED_TO_FORM)){// Now we need to add ourselves to the formnsAutoStringnameVal,idVal;GetAttr(kNameSpaceID_None,nsGkAtoms::name,nameVal);GetAttr(kNameSpaceID_None,nsGkAtoms::id,idVal);SetFlags(ADDED_TO_FORM);// Notify only if we just found this mForm.mForm->AddElement(this,true,oldForm==nullptr);if(!nameVal.IsEmpty()){mForm->AddElementToTable(this,nameVal);}if(!idVal.IsEmpty()){mForm->AddElementToTable(this,idVal);}}if(mForm!=oldForm||needStateUpdate){UpdateState(true);}}voidnsGenericHTMLFormElement::UpdateFieldSet(boolaNotify){nsIContent*parent=nullptr;nsIContent*prev=nullptr;for(parent=GetParent();parent;prev=parent,parent=parent->GetParent()){HTMLFieldSetElement*fieldset=HTMLFieldSetElement::FromContent(parent);if(fieldset&&(!prev||fieldset->GetFirstLegend()!=prev)){if(mFieldSet==fieldset){// We already have the right fieldset;return;}if(mFieldSet){mFieldSet->RemoveElement(this);}mFieldSet=fieldset;fieldset->AddElement(this);// The disabled state may have changedFieldSetDisabledChanged(aNotify);return;}}// No fieldset found.if(mFieldSet){mFieldSet->RemoveElement(this);mFieldSet=nullptr;// The disabled state may have changedFieldSetDisabledChanged(aNotify);}}voidnsGenericHTMLFormElement::FieldSetDisabledChanged(boolaNotify){UpdateState(aNotify);}boolnsGenericHTMLFormElement::IsLabelable()const{// TODO: keygen should be in that list, see bug 101019.uint32_ttype=ControlType();return(type&NS_FORM_INPUT_ELEMENT&&type!=NS_FORM_INPUT_HIDDEN)||type&NS_FORM_BUTTON_ELEMENT||// type == NS_FORM_KEYGEN ||type==NS_FORM_OUTPUT||type==NS_FORM_SELECT||type==NS_FORM_TEXTAREA;}//----------------------------------------------------------------------voidnsGenericHTMLElement::Click(CallerTypeaCallerType){if(HandlingClick())return;// Strong in case the event kills itnsCOMPtr<nsIDocument>doc=GetComposedDoc();nsCOMPtr<nsIPresShell>shell;RefPtr<nsPresContext>context;if(doc){shell=doc->GetShell();if(shell){context=shell->GetPresContext();}}SetHandlingClick();// Mark this event trusted if Click() is called from system code.WidgetMouseEventevent(aCallerType==CallerType::System,eMouseClick,nullptr,WidgetMouseEvent::eReal);event.mFlags.mIsPositionless=true;event.inputSource=nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;EventDispatcher::Dispatch(static_cast<nsIContent*>(this),context,&event);ClearHandlingClick();}boolnsGenericHTMLElement::IsHTMLFocusable(boolaWithMouse,bool*aIsFocusable,int32_t*aTabIndex){nsIDocument*doc=GetComposedDoc();if(!doc||doc->HasFlag(NODE_IS_EDITABLE)){// In designMode documents we only allow focusing the document.if(aTabIndex){*aTabIndex=-1;}*aIsFocusable=false;returntrue;}int32_ttabIndex=TabIndex();booldisabled=false;booldisallowOverridingFocusability=true;if(IsEditableRoot()){// Editable roots should always be focusable.disallowOverridingFocusability=true;// Ignore the disabled attribute in editable contentEditable/designMode// roots.if(!HasAttr(kNameSpaceID_None,nsGkAtoms::tabindex)){// The default value for tabindex should be 0 for editable// contentEditable roots.tabIndex=0;}}else{disallowOverridingFocusability=false;// Just check for disabled attribute on form controlsdisabled=IsDisabled();if(disabled){tabIndex=-1;}}if(aTabIndex){*aTabIndex=tabIndex;}// If a tabindex is specified at all, or the default tabindex is 0, we're focusable*aIsFocusable=(tabIndex>=0||(!disabled&&HasAttr(kNameSpaceID_None,nsGkAtoms::tabindex)));returndisallowOverridingFocusability;}voidnsGenericHTMLElement::RegUnRegAccessKey(boolaDoReg){// first check to see if we have an access keynsAutoStringaccessKey;GetAttr(kNameSpaceID_None,nsGkAtoms::accesskey,accessKey);if(accessKey.IsEmpty()){return;}// We have an access key, so get the ESM from the pres context.nsPresContext*presContext=GetPresContext(eForUncomposedDoc);if(presContext){EventStateManager*esm=presContext->EventStateManager();// Register or unregister as appropriate.if(aDoReg){esm->RegisterAccessKey(this,(uint32_t)accessKey.First());}else{esm->UnregisterAccessKey(this,(uint32_t)accessKey.First());}}}boolnsGenericHTMLElement::PerformAccesskey(boolaKeyCausesActivation,boolaIsTrustedEvent){nsPresContext*presContext=GetPresContext(eForUncomposedDoc);if(!presContext){returnfalse;}// It's hard to say what HTML4 wants us to do in all cases.boolfocused=true;nsFocusManager*fm=nsFocusManager::GetFocusManager();if(fm){fm->SetFocus(this,nsIFocusManager::FLAG_BYKEY);// Return true if the element became the current focus within its window.nsPIDOMWindowOuter*window=OwnerDoc()->GetWindow();focused=(window&&window->GetFocusedNode());}if(aKeyCausesActivation){// Click on it if the users prefs indicate to do so.nsAutoPopupStatePusherpopupStatePusher(aIsTrustedEvent?openAllowed:openAbused);DispatchSimulatedClick(this,aIsTrustedEvent,presContext);}returnfocused;}nsresultnsGenericHTMLElement::DispatchSimulatedClick(nsGenericHTMLElement*aElement,boolaIsTrusted,nsPresContext*aPresContext){WidgetMouseEventevent(aIsTrusted,eMouseClick,nullptr,WidgetMouseEvent::eReal);event.inputSource=nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;event.mFlags.mIsPositionless=true;returnEventDispatcher::Dispatch(ToSupports(aElement),aPresContext,&event);}already_AddRefed<nsIEditor>nsGenericHTMLElement::GetAssociatedEditor(){// If contenteditable is ever implemented, it might need to do something different here?RefPtr<TextEditor>textEditor=GetTextEditorInternal();returntextEditor.forget();}boolnsGenericHTMLElement::IsCurrentBodyElement(){// TODO Bug 698498: Should this handle the case where GetBody returns a// frameset?if(!IsHTMLElement(nsGkAtoms::body)){returnfalse;}nsCOMPtr<nsIDOMHTMLDocument>htmlDocument=do_QueryInterface(GetUncomposedDoc());if(!htmlDocument){returnfalse;}nsCOMPtr<nsIDOMHTMLElement>htmlElement;htmlDocument->GetBody(getter_AddRefs(htmlElement));returnhtmlElement==static_cast<HTMLBodyElement*>(this);}// staticvoidnsGenericHTMLElement::SyncEditorsOnSubtree(nsIContent*content){/* Sync this node */nsGenericHTMLElement*element=FromContent(content);if(element){nsCOMPtr<nsIEditor>editor=element->GetAssociatedEditor();if(editor){editor->SyncRealTimeSpell();}}/* Sync all children */for(nsIContent*child=content->GetFirstChild();child;child=child->GetNextSibling()){SyncEditorsOnSubtree(child);}}voidnsGenericHTMLElement::RecompileScriptEventListeners(){int32_ti,count=mAttrsAndChildren.AttrCount();for(i=0;i<count;++i){constnsAttrName*name=mAttrsAndChildren.AttrNameAt(i);// Eventlistenener-attributes are always in the null namespaceif(!name->IsAtom()){continue;}nsIAtom*attr=name->Atom();if(!IsEventAttributeName(attr)){continue;}nsAutoStringvalue;GetAttr(kNameSpaceID_None,attr,value);SetEventHandler(attr,value,true);}}boolnsGenericHTMLElement::IsEditableRoot()const{nsIDocument*document=GetComposedDoc();if(!document){returnfalse;}if(document->HasFlag(NODE_IS_EDITABLE)){returnfalse;}if(GetContentEditableValue()!=eTrue){returnfalse;}nsIContent*parent=GetParent();return!parent||!parent->HasFlag(NODE_IS_EDITABLE);}staticvoidMakeContentDescendantsEditable(nsIContent*aContent,nsIDocument*aDocument){// If aContent is not an element, we just need to update its// internal editable state and don't need to notify anyone about// that. For elements, we need to send a ContentStateChanged// notification.if(!aContent->IsElement()){aContent->UpdateEditableState(false);return;}Element*element=aContent->AsElement();element->UpdateEditableState(true);for(nsIContent*child=aContent->GetFirstChild();child;child=child->GetNextSibling()){if(!child->HasAttr(kNameSpaceID_None,nsGkAtoms::contenteditable)){MakeContentDescendantsEditable(child,aDocument);}}}voidnsGenericHTMLElement::ChangeEditableState(int32_taChange){//XXXsmaug Fix this for Shadow DOM, bug 1066965.nsIDocument*document=GetUncomposedDoc();if(!document){return;}if(aChange!=0){nsCOMPtr<nsIHTMLDocument>htmlDocument=do_QueryInterface(document);if(htmlDocument){htmlDocument->ChangeContentEditableCount(this,aChange);}nsIContent*parent=GetParent();while(parent){parent->ChangeEditableDescendantCount(aChange);parent=parent->GetParent();}}if(document->HasFlag(NODE_IS_EDITABLE)){document=nullptr;}// MakeContentDescendantsEditable is going to call ContentStateChanged for// this element and all descendants if editable state has changed.// We might as well wrap it all in one script blocker.nsAutoScriptBlockerscriptBlocker;MakeContentDescendantsEditable(this,document);}//----------------------------------------------------------------------nsGenericHTMLFormElementWithState::nsGenericHTMLFormElementWithState(already_AddRefed<mozilla::dom::NodeInfo>&aNodeInfo,uint8_taType):nsGenericHTMLFormElement(aNodeInfo,aType){mStateKey.SetIsVoid(true);}nsresultnsGenericHTMLFormElementWithState::GenerateStateKey(){// Keep the key if already computedif(!mStateKey.IsVoid()){returnNS_OK;}nsIDocument*doc=GetUncomposedDoc();if(!doc){returnNS_OK;}// Generate the state keynsresultrv=nsContentUtils::GenerateStateKey(this,doc,mStateKey);if(NS_FAILED(rv)){mStateKey.SetIsVoid(true);returnrv;}// If the state key is blank, this is anonymous content or for whatever// reason we are not supposed to save/restore state: keep it as such.if(!mStateKey.IsEmpty()){// Add something unique to content so layout doesn't muck us up.mStateKey+="-C";}returnNS_OK;}nsPresState*nsGenericHTMLFormElementWithState::GetPrimaryPresState(){if(mStateKey.IsEmpty()){returnnullptr;}nsCOMPtr<nsILayoutHistoryState>history=GetLayoutHistory(false);if(!history){returnnullptr;}// Get the pres state for this key, if it doesn't exist, create one.nsPresState*result=history->GetState(mStateKey);if(!result){result=newnsPresState();history->AddState(mStateKey,result);}returnresult;}already_AddRefed<nsILayoutHistoryState>nsGenericHTMLFormElementWithState::GetLayoutHistory(boolaRead){nsCOMPtr<nsIDocument>doc=GetUncomposedDoc();if(!doc){returnnullptr;}//// Get the history//nsCOMPtr<nsILayoutHistoryState>history=doc->GetLayoutHistoryState();if(!history){returnnullptr;}if(aRead&&!history->HasStates()){returnnullptr;}returnhistory.forget();}boolnsGenericHTMLFormElementWithState::RestoreFormControlState(){if(mStateKey.IsEmpty()){returnfalse;}nsCOMPtr<nsILayoutHistoryState>history=GetLayoutHistory(true);if(!history){returnfalse;}nsPresState*state;// Get the pres state for this keystate=history->GetState(mStateKey);if(state){boolresult=RestoreState(state);history->RemoveState(mStateKey);returnresult;}returnfalse;}voidnsGenericHTMLFormElementWithState::NodeInfoChanged(nsIDocument*aOldDoc){nsGenericHTMLElement::NodeInfoChanged(aOldDoc);mStateKey.SetIsVoid(true);}nsSizensGenericHTMLElement::GetWidthHeightForImage(RefPtr<imgRequestProxy>&aImageRequest){nsSizesize(0,0);nsIFrame*frame=GetPrimaryFrame(FlushType::Layout);if(frame){size=frame->GetContentRect().Size();size.width=nsPresContext::AppUnitsToIntCSSPixels(size.width);size.height=nsPresContext::AppUnitsToIntCSSPixels(size.height);}else{constnsAttrValue*value;nsCOMPtr<imgIContainer>image;if(aImageRequest){aImageRequest->GetImage(getter_AddRefs(image));}if((value=GetParsedAttr(nsGkAtoms::width))&&value->Type()==nsAttrValue::eInteger){size.width=value->GetIntegerValue();}elseif(image){image->GetWidth(&size.width);}if((value=GetParsedAttr(nsGkAtoms::height))&&value->Type()==nsAttrValue::eInteger){size.height=value->GetIntegerValue();}elseif(image){image->GetHeight(&size.height);}}NS_ASSERTION(size.width>=0,"negative width");NS_ASSERTION(size.height>=0,"negative height");returnsize;}boolnsGenericHTMLElement::IsEventAttributeName(nsIAtom*aName){returnnsContentUtils::IsEventAttributeName(aName,EventNameType_HTML);}/** * Construct a URI from a string, as an element.src attribute * would be set to. Helper for the media elements. */nsresultnsGenericHTMLElement::NewURIFromString(constnsAString&aURISpec,nsIURI**aURI){NS_ENSURE_ARG_POINTER(aURI);*aURI=nullptr;nsCOMPtr<nsIDocument>doc=OwnerDoc();nsCOMPtr<nsIURI>baseURI=GetBaseURI();nsresultrv=nsContentUtils::NewURIWithDocumentCharset(aURI,aURISpec,doc,baseURI);NS_ENSURE_SUCCESS(rv,rv);boolequal;if(aURISpec.IsEmpty()&&doc->GetDocumentURI()&&NS_SUCCEEDED(doc->GetDocumentURI()->Equals(*aURI,&equal))&&equal){// Assume an element can't point to a fragment of its embedding// document. Fail here instead of returning the recursive URI// and waiting for the subsequent load to fail.NS_RELEASE(*aURI);returnNS_ERROR_DOM_INVALID_STATE_ERR;}returnNS_OK;}staticboolIsOrHasAncestorWithDisplayNone(Element*aElement,nsIPresShell*aPresShell){nsTArray<Element*>elementsToCheck;for(Element*e=aElement;e;e=e->GetParentElement()){if(e->GetPrimaryFrame()){// e definitely isn't display:none and doesn't have a display:none// ancestor.break;}elementsToCheck.AppendElement(e);}if(elementsToCheck.IsEmpty()){returnfalse;}// XXXbholley: This could be done more directly with Servo's style system.StyleSetHandlestyleSet=aPresShell->StyleSet();RefPtr<nsStyleContext>sc;for(int32_ti=elementsToCheck.Length()-1;i>=0;--i){if(sc){sc=styleSet->ResolveStyleFor(elementsToCheck[i],sc,LazyComputeBehavior::Assert);}else{sc=nsComputedDOMStyle::GetStyleContextNoFlush(elementsToCheck[i],nullptr,aPresShell);}if(sc->StyleDisplay()->mDisplay==StyleDisplay::None){returntrue;}}returnfalse;}voidnsGenericHTMLElement::GetInnerText(mozilla::dom::DOMString&aValue,mozilla::ErrorResult&aError){if(!GetPrimaryFrame(FlushType::Layout)){nsIPresShell*presShell=nsComputedDOMStyle::GetPresShellForContent(this);if(!presShell||IsOrHasAncestorWithDisplayNone(this,presShell)){GetTextContentInternal(aValue,aError);return;}}nsRange::GetInnerTextNoFlush(aValue,aError,this,0,this,GetChildCount());}voidnsGenericHTMLElement::SetInnerText(constnsAString&aValue){// Batch possible DOMSubtreeModified events.mozAutoSubtreeModifiedsubtree(OwnerDoc(),nullptr);FireNodeRemovedForChildren();// Might as well stick a batch around this since we're performing several// mutations.mozAutoDocUpdateupdateBatch(GetComposedDoc(),UPDATE_CONTENT_MODEL,true);nsAutoMutationBatchmb;uint32_tchildCount=GetChildCount();mb.Init(this,true,false);for(uint32_ti=0;i<childCount;++i){RemoveChildAt(0,true);}mb.RemovalDone();nsStringstr;constchar16_t*s=aValue.BeginReading();constchar16_t*end=aValue.EndReading();while(true){if(s!=end&&*s=='\r'&&s+1!=end&&s[1]=='\n'){// a \r\n pair should only generate one <br>, so just skip the \r++s;}if(s==end||*s=='\r'||*s=='\n'){if(!str.IsEmpty()){RefPtr<nsTextNode>textContent=newnsTextNode(NodeInfo()->NodeInfoManager());textContent->SetText(str,true);AppendChildTo(textContent,true);}if(s==end){break;}str.Truncate();already_AddRefed<mozilla::dom::NodeInfo>ni=NodeInfo()->NodeInfoManager()->GetNodeInfo(nsGkAtoms::br,nullptr,kNameSpaceID_XHTML,nsIDOMNode::ELEMENT_NODE);RefPtr<HTMLBRElement>br=newHTMLBRElement(ni);AppendChildTo(br,true);}else{str.Append(*s);}++s;}mb.NodesAdded();}